#define _XOPEN_SOURCE
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<fcntl.h>
#define SIZE 1024
#define MAX_ARGC 30//最大命令行字符串个数
#define SEP " "//设置分隔符为空格
char*argv[MAX_ARGC];
int lastcode;//最近一次进程退出码
enum redirection{
  No_redir,
  In_redir,
  Out_redir,
  App_redir
};
int redir=No_redir;
char redirfile[30];
void Extractfile(char*str)
{
  int cur=0;
  while(str[cur]==' ')cur++;
  strcpy(redirfile,str+cur);
}
int Interactive(char commandline[],int size)
{
  printf("[%s@%s %s]$ ",getenv("USER"),getenv("HOSTNAME"),getenv("PWD"));
  fgets(commandline,size,stdin);
  commandline[strlen(commandline)-1]='\0';
  int end=strlen(commandline)-1;
  while(end>=0)
  {
    if(commandline[end]=='>')
    {
      if(commandline[end-1]=='>')
      {
        redir=App_redir;
        commandline[end-1]='\0';
        Extractfile(commandline+end+1);
        break;
      }
      else
      {
        redir=Out_redir;
        commandline[end]='\0';
        Extractfile(commandline+end+1);
        break;
      }

    }
    else if(commandline[end]=='<')
    {
      redir=In_redir;
      commandline[end]='\0';
      Extractfile(commandline+end+1);
      break;
    }
    else end--;
  }
  return strlen(commandline);
}
void Splitstr(char commandline[])
{
  int i=0;
  argv[i++]=strtok(commandline,SEP);
  while(argv[i++]=strtok(NULL,SEP));
  if(strcmp("ls",argv[0])==0)
  {
    argv[i-1]="--color";
    argv[i]=NULL;
  }
}
void Execute()
{
  if(strcmp("ll",argv[0])==0&&!argv[1])//特别处理ll
  {
    argv[0]="ls";
    argv[1]="-l";
  }
  pid_t id=fork();
  if(id==0)
  {
    if(redir==In_redir)
    {
      int fp=open(redirfile,O_RDONLY);
      dup2(fp,0);
    }
    else if(redir==Out_redir)
    {
      int fp=open(redirfile,O_WRONLY|O_CREAT|O_TRUNC,0666);
      dup2(fp,1);
    }
    else if(redir==App_redir)
    {
      int fp=open(redirfile,O_WRONLY|O_CREAT|O_APPEND,0666);
      dup2(fp,1); 
    }
    execvp(argv[0],argv);
    printf("mybash: ");//只有进程程序替换失败才会走到下边
    for(int i=0;argv[i];i++)printf("%s ",argv[i]);
    printf(": not found your command\n");
    exit(2);
  }
  redir=No_redir;
  int status=0;
  pid_t rid=waitpid(id,&status,0);
  if(rid>0)lastcode=WEXITSTATUS(status);
}
int Bulidincmd()
{
  int ret=0;
  if(strcmp("cd",argv[0])==0)
  {
    ret=1;
    char*target=argv[1];
    if(!target)target=getenv("HOME");
    chdir(target);
    char tmp[SIZE];
    snprintf(tmp,SIZE,"PWD=%s",target);
    putenv(tmp);
  }
  else if(strcmp("export",argv[0])==0)
  {
    ret=1;
    if(argv[1])
    {
      char tmp[SIZE];
      strncpy(tmp,argv[1]+1,strlen(argv[1])-2);
      putenv(tmp);
    }
  }
  else if(strcmp("echo",argv[0])==0)
  {
    ret=1;
    if(argv[1]&&argv[1][0]=='$')
    {
      if(argv[1][1]=='?'&&!argv[2])
      {
        printf("%d\n",lastcode);
        lastcode=0;
      }
      else
      {
        char* tmp=getenv(argv[1]+1);
        if(tmp)printf("%s\n",tmp);
      }
    }
    else
    {
        for(int i=1;argv[i];i++)printf("%s ",argv[i]);
        printf("\n");
    }
  }
  lastcode=0;
  return ret;
}
int main()
{
  while(1)
  {
  char commandline[SIZE];
  //打印命令行提示符，获取用户输入的命令字符串
  int n=Interactive(commandline,SIZE);
  if(n==0)continue;
  //分割字符串成命令行参数
  Splitstr(commandline);
  //处理内建命令
  n=Bulidincmd();
  if(n==1)continue;
  //执行命令
  Execute(); 
 }
  return 0;
}
